#include <linux/module.h>
#include <linux/kernel.h> /* printk() */
#include <asm/uaccess.h> /* copy_from/to_user */
#include <linux/fs.h> /* file_operations */
#include <linux/miscdevice.h>

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Ryan Welton <Ryan.G.Welton@gmail.com>");
MODULE_DESCRIPTION("Buggered Linux Device for exploitation");
MODULE_VERSION("1.3.3.7");


#define LEAK_KSTACK_ADDR 0xFF
#define KWRITE 0xBB

static long stack_jack_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{

  int res;

  unsigned long * write_addr;

  switch (cmd) {
    case LEAK_KSTACK_ADDR:
       res = put_user((unsigned long) &res, (unsigned long *) arg);
       break;
    case KWRITE:
       res = get_user(write_addr,(unsigned long *) arg);
       if(res < 0){
          return res;
       }
       *write_addr = 0xFFFFFFF;
       break;
    default :
       printk("Unknown ioctl cmd: %d", cmd);
       return -1;
  }
  return 0;
}

static struct file_operations stack_jack_fops = {
  unlocked_ioctl: stack_jack_ioctl
};


static struct miscdevice stack_jack_dev = {
        minor: MISC_DYNAMIC_MINOR,
        name: "stack_jack",
        fops: &stack_jack_fops,
        mode: 777
};

static int __init mod_begin(void)
{
   int ret;
   ret = misc_register(&stack_jack_dev);
   if(ret)
     printk("Failed to register misc device");
   else
     printk("Module successfully loaded");

   return ret;//A non 0 return means init_module failed; module can't be loaded.
}

static void __exit mod_exit(void)
{
  int ret = misc_deregister(&stack_jack_dev);
  if(ret)
    printk("There was an error unregistering device");
}

module_init(mod_begin);
module_exit(mod_exit);
